package DDSDownloadServer;

import DDSInterfaces.ServerBandwidthBean;

import jade.core.*;
import jade.core.Agent;
import jade.core.behaviours.*;
import jade.lang.acl.*;
import jade.content.*;
import jade.content.lang.sl.*;
import jade.content.onto.basic.*;
import jade.domain.mobility.*;
import jade.domain.JADEAgentManagement.*;
import java.util.*;

/**
 *
 * @author Bo Visfeldt
 * @author Rasmus Bo Sorensen
 */
public class QueryAgent extends Agent{
    private ArrayList<ServerInfo> serverList = new ArrayList();
    private int nextServerIndex = 0;
    private String aTitle = "";
    private Location nextServer = null;
    private ServerBandwidthBean maxBandwidthBean = new ServerBandwidthBean("", 0);
    private String clientSignPost = "";

    @Override
    protected void setup(){
        // The parameters passed on from the DownloadServer are saved in local variables.
        Object[] args = getArguments();
        System.out.println(args.length);
        aTitle = (String) args[0];
        clientSignPost = (String) args[1];
        serverList = (ArrayList<ServerInfo>)args[2];
        init();
        moveToNextServer();
        addBehaviour(new Start(this));
    }

    protected boolean moveToNextServer(){
        // FIXME The timeout should be set to a suiting amout of time.
        long timeout = 5000;
        // The location of the next Fileserver is fetched
        WhereIsAgentAction wa = new WhereIsAgentAction();
        if (nextServerIndex < serverList.size()){
            wa.setAgentIdentifier(new AID(serverList.get(nextServerIndex).getName(), AID.ISLOCALNAME));
        }
        else{
            // When the end of the serverList is reached, the agent should be moved back to the clientContainer.
            wa.setAgentIdentifier(new AID(clientSignPost,AID.ISLOCALNAME));
        }
        sendRequest(new Action(getAMS(), wa));
        MessageTemplate mt = MessageTemplate.and(
			  MessageTemplate.MatchSender(getAMS()),
			  MessageTemplate.MatchPerformative(ACLMessage.INFORM));
        ACLMessage resp = blockingReceive(mt,timeout);
        if (resp != null){
            // FIXME Make a time out for the message of receiving the next server and go to the next server if the timeout is reached.
            try{
                ContentElement ce = getContentManager().extractContent(resp);
                Result result = (Result) ce;
                System.out.println("Location of next ServerAgent is: " + result.getValue());
                nextServer = (Location) result.getValue();
            }
            catch(Exception e){
                e.printStackTrace();
            }
            if(nextServer != null){
                doMove(nextServer);
                return true;
            }
            else{
                return false;
            }
        }
        else{
            return false;
        }
    }

    protected void sendRequest(Action action) {
        // This method sends the request of moving the Agent to the specified container
        ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
        request.setLanguage(new SLCodec().getName());
        request.setOntology(MobilityOntology.getInstance().getName());
        try {
            getContentManager().fillContent(request, action);
            request.addReceiver(action.getActor());
            send(request);
        }
        catch (Exception ex) { ex.printStackTrace(); }
   }

    protected void init(){
        // This disapears each time the Agent is moved
        getContentManager().registerLanguage(new SLCodec());
	getContentManager().registerOntology(MobilityOntology.getInstance());
    }

    @Override
    protected void beforeMove(){
        System.out.println("Moving now to location : " + nextServer.toString());
    }

    @Override
    protected void afterMove(){
        init(); // init() method has to be called after every move.
        System.out.println("Agent arrived at: " + here().toString());
    }

    class Start extends CyclicBehaviour{
        public Start(Agent a){
            super(a);
        }

        public void action(){
            // Query aTitle from fileserver, by sending a message.
            if(nextServerIndex < serverList.size()){
                ACLMessage msg = new ACLMessage(ACLMessage.QUERY_REF);
                msg.setContent( aTitle );
                msg.addReceiver( new AID( serverList.get(nextServerIndex).getName(), AID.ISLOCALNAME) );
                send(msg);
                ACLMessage reply = blockingReceive();
                if(reply.getPerformative() == ACLMessage.INFORM){
                    int resultingBandwidth  = Integer.parseInt(reply.getContent());
                    if( maxBandwidthBean.getServerBandwidth() < resultingBandwidth){
                        maxBandwidthBean = new ServerBandwidthBean(serverList.get(nextServerIndex).getName(), resultingBandwidth);
                    }
                }
                do{
                    nextServerIndex++;
                } while (!moveToNextServer()); // Try again if Move did not succeed
            }
            else{
                System.out.println("\n-------------------------------------------------");
                System.out.println("Bandwidth query done...");
                System.out.println("Maximum bandwidth found @" + maxBandwidthBean.getServerAddress() + " : " + maxBandwidthBean.getServerBandwidth() + " Kb/s");
                System.out.println("-------------------------------------------------\n");
                doDelete();
            }
        }
    }
}
